package com.kindnesslibrary.network.retrofit.invocation;

import android.os.Handler;
import android.os.Message;

import com.alibaba.fastjson.JSONObject;
import com.kindnesslibrary.network.HttpManager;
import com.kindnesslibrary.network.callback.HttpCallBack;
import com.kindnesslibrary.network.get.GetFormThread;
import com.kindnesslibrary.network.post.PostFormThread;
import com.kindnesslibrary.network.retrofit.reflect.Body;
import com.kindnesslibrary.network.retrofit.reflect.FilePart;
import com.kindnesslibrary.network.retrofit.reflect.GET;
import com.kindnesslibrary.network.retrofit.reflect.Multipart;
import com.kindnesslibrary.network.retrofit.reflect.POST;
import com.kindnesslibrary.network.retrofit.reflect.Param;
import com.kindnesslibrary.network.upload.SingleUploadFileThread;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import rx.Observable;
import rx.Subscriber;

/**
 * 代理方法，通过这个类与网络读取数据，然后用rxjava思想进行返回数据
 */
public class MethodProxy implements InvocationHandler {

    @Override
    public Object invoke(Object o, final Method method, Object[] objects) throws Throwable {
        final POST post = method.getAnnotation(POST.class);
        final GET get = method.getAnnotation(GET.class);
        final Multipart multipart = method.getAnnotation(Multipart.class);
        if(post == null && get == null && multipart == null){
            new Throwable("method no be annotation");
        }
        Annotation[][] annotations = method.getParameterAnnotations();
        final Map<String, String> postMap = new HashMap<>();
        File file = null;
        String fileParams = null;
        if(annotations != null){
            for(int i = 0; i < annotations.length; i++){
                Annotation annotation = annotations[i][0];
                if(annotation instanceof Param) {
                    Param path = (Param) annotations[i][0];
                    if (objects[i] != null && !"".equals(objects[i] + "")) {
                        postMap.put(path.value(), objects[i] + "");
                    }
                } else if(annotation instanceof Body){
                    Object object = objects[i];
                    Map<String, Object> paramMap = JSONObject.parseObject(JSONObject.toJSONString(object), Map.class);
                    for(String key : paramMap.keySet()){
                        Object value = paramMap.get(key);
                        if(value != null && !"".equals(value + "")){
                            postMap.put(key, value + "");
                        }
                    }
                } else if(annotation instanceof FilePart){
                    fileParams = ((FilePart) annotation).value();
                    Object object = objects[i];
                    if(object instanceof File || fileParams == null || fileParams == "") {
                        file = (File) object;
                    }else{
                        throw new Exception("参数必须为File参数");
                    }
                }
            }
        }
        if(multipart != null){
            if(post == null){
                throw new Exception("multipart method no have post annotation");
            }
            if(file == null){
                throw new Exception("file参数必须不为空");
            }
        }
        String returnType = method.getReturnType().getName();
        final String fp = fileParams;
        final File uploadFile = file;
        if(Observable.class.getName().equals(returnType)){
            Observable observable = Observable.create( new Observable.OnSubscribe<Object>() {
                @Override
                public void call(Subscriber subscriber) {
                    Type type = method.getGenericReturnType();
                    if(post != null && multipart == null){
                        post(post.url(), postMap, subscriber, (ParameterizedType) type); // post请求
                    }else if(get != null){
                        get(get.url(), postMap, subscriber, (ParameterizedType) type); // get请求
                    } else if(multipart != null){
                        upload(uploadFile, post.url(), fp, postMap, subscriber, (ParameterizedType) type); // 文件上传
                    }
                }
            });
            return observable;
        }
        return new Object();
    }

    /**
     * post请求
     * @param url 路径
     * @param params 参数
     * @param subscriber
     * @param type
     */
    public void post(String url, Map<String, String> params, final Subscriber<? super Object> subscriber, ParameterizedType type){
        HttpManager.getInstance().addPostFormCallBack(new PostFormThread(url, params, handler, new HttpOperaCallBack(subscriber, type)));
    }

    /**
     * get请求
     * @param url 路径
     * @param params 参数
     * @param subscriber
     * @param type
     */
    public void get(String url, Map<String, String> params, final Subscriber<? super Object> subscriber, ParameterizedType type){
        HttpManager.getInstance().addGetFormCallBack(new GetFormThread(url, params, handler, new HttpOperaCallBack(subscriber, type)));
    }

    /**
     * 文件上传
     * @param uploadFile 将要上传文件
     * @param url 路径
     * @param fileParam 文件参数名称
     * @param params 参数
     * @param subscriber
     * @param type
     */
    public void upload(File uploadFile, String url, String fileParam, Map<String, String> params,
                       final Subscriber<? super Object> subscriber, ParameterizedType type){
        HttpManager.getInstance().addSingleFUCallBack(new SingleUploadFileThread(
                uploadFile, url, fileParam, params, handler, new HttpOperaCallBack(subscriber, type)));
    }

    Handler handler = new Handler(){
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);

        }
    };

    class HttpOperaCallBack implements HttpCallBack{

        private Subscriber subscriber;
        private ParameterizedType genericity;

        public HttpOperaCallBack(Subscriber subscriber, ParameterizedType genericity){
            this.subscriber = subscriber;
            this.genericity = genericity;
        }

        @Override
        public void onRequestOk(Object obj) {
            if(obj == null || "".equals((String)obj)){
                return;
            }
            Object object = JSONObject.parseObject((String)obj, genericity.getActualTypeArguments()[0]);
            if(!subscriber.isUnsubscribed()) {
                subscriber.onNext(object);
            }
            if(!subscriber.isUnsubscribed()) {
                subscriber.onCompleted();
            }
        }

        @Override
        public void onError(String msg) {

        }

        @Override
        public void onCancel() {

        }
    }

}
